Configuraciones Iniciales para R

Antes de comenzar con nuestra optimización de cartera, utilizando la teoría del portafolio de Markowitz, designaremos las configuraciones iniciales para el trabajo, comenzando con la verificación, instalación y carga de los paquetes a utilizar para el caso, luego de ello, al mismo tiempo hacemos unas configuraciones aparte para el entorno de trabajo propiamente tal (no es necesario para el markdown, sin embargo, para aquellos que quieran replicar el modelo, les sea útil), con esto todo

knitr::opts_chunk$set(echo = TRUE, include = TRUE, fig.align = "center",fig.width = 10, fig.height = 8, message = FALSE, warning = FALSE)
#############################################################################
# Portfolio Opimization
# Author: Matías Vicuña Cofré
#############################################################################
#******************** Configuraciones e Inicializacion *********************#
#############################################################################
{
  # Librerías
  {
    # Lista de paquetes que quieres verificar
    paquetes <- c("tidyverse","readxl","janitor","skimr","scales","ggthemes",
                  "tseries","fPortfolio","knitr","kableExtra","gplots",
                  "plotly", "lubridate","gplots","formattable")
    
    # Verificar e instalar paquetes que no estén instalados
    for (paquete in paquetes) {
      if (!require(paquete, character.only = TRUE)) {
        install.packages(paquete)
      }
    }
    remove(paquetes)
    
    # Activacion Librerias
    suppressPackageStartupMessages({
      library(tidyverse)
      library(readxl)
      library(janitor)
      library(skimr)
      library(scales)
      library(ggthemes)
      library(tseries)
      library(fPortfolio)
      library(knitr)
      library(kableExtra)
      library(plotly)
      library(lubridate)
      library(gplots)
      library(formattable)
    })
  }
  # Configuraciones Entorno de Trabajo
  {
    # Limpiamos el entorno de trabajo
    rm(list = ls())
    
    # Limpiamos la Memoria (RAM)
    gc(reset = TRUE)
    
    # Limpiamos la consola
    cat("\014")
    
    # De número científico a natural
    options(scipen = 999)
  }
}

Comenzando el Modelo

Luego de las configuraciones, generamos la primera muestra de datos a utilizar, usando el paquete tseries, como primer ejemplo, utilizaremos el índice S&P 500 Dow Jones, al cuál observaremo su precio histórico desde Enero del 2000 hasta el 31 de diciembre del 2023, usaremos su ticket de Yahoo Finance (^GSPC) (veáse más detalle del índice aquí).

Junto con ello, usamos el paquete skimr para realizar un análisis estadístico básico de la serie con los precios históricos, teniendo su media, percentiles y demás detalles.

# Carga serie S&P 500.
SP500 <- get.hist.quote(
  instrument = "^GSPC",
  start = as.Date("2000-01-01"),
  end = as.Date("2023-12-31"),
  quote = "AdjClose"
)
## time series starts 2000-01-03
## time series ends   2023-12-29
# Renombramos la base original
colnames(SP500) <- "SP500"

# Ajustamos la muestra
SP_500 <- SP500 %>%
  as_tibble() %>% 
  mutate(Fecha = as_date(time(SP500))) %>% 
  rename(Precio = SP500)

# Generamos tabla resumen de precios históricos
formattable(skim_without_charts(SP_500$Precio))
skim_type skim_variable n_missing complete_rate numeric.mean numeric.sd numeric.p0 numeric.p25 numeric.p50 numeric.p75 numeric.p100
numeric data 0 1 1973.587 1061.336 676.53 1191.38 1457.34 2584.84 4796.56

Ya teniendo la serie cargada, generamos ahora un pequeño gráfico que entrega el rendimiento histórico desde el 2000 al 2023 del precio ajustado del indicador.

Para ello, hacemos uso de un recursos super relevantes para el análisis y visualización de datos: ggplot2, con este paquete y usando de adicional para la interacción el paquete plotly, tenemos un gráfico que nos entrega en detalle e intuitivamente el desarrollo de este mercado Norteamericano.

# Generamos el gráfico
int_plot_SP500 <- SP_500 %>%
  ggplot(mapping = aes(x = Fecha,
                       y = Precio)) +
  geom_line(aes(y = Precio),
            color = "blue4") +
  labs(x = "Años",
       y = "Precio $USD",
       title = "Precio Ajustado S&P 500",
       subtitle = "En dólares") +
  
  theme_minimal() +
  theme(axis.title.x = element_text(size = 12, 
                                    face = "bold"),
        axis.title.y = element_text(size = 12, 
                                    face = "bold"),
        plot.title = element_text(size = 20,
                                  face = "bold", 
                                  hjust = 0.5),
        plot.subtitle = element_text(size = 20,
                                  face = "bold", 
                                  hjust = 0.5))

# Generamos el gráfico de forma interactiva
ggplotly(int_plot_SP500)

Siguiendo con esta ídea, ahora generaremos una cartera, la cuál se compondrá de a lo menos 10 tipos de empresas, para este ejemplo, usaremos empresas que cotizan en la bolsa de Nueva York, especificamente serán las siguientes:

Con este listado de empresas, ahora construiremos nuestra base.

Consolidando la cartera

# Datos Previos
tickets <- c("KO", "PEP", "JNJ", "WMT", "TGT", "AAPL", "MSFT", "AMZN")
portafolio <- tibble()
start_port <- as.Date("2000-01-01")
end_port <- as.Date("2023-12-31")

# Iteración de Recopilación de Series
for (i in seq_along(tickets)) {
  data <- get.hist.quote(
    instrument = tickets[i],
    start = start_port,
    end = end_port,
    quote = "Adjusted"
  )

  # Verifica si el objeto portafolio está vacío
  if (nrow(portafolio) == 0) {
    portafolio <- data
  } else {
    # Combina las series temporales por columna
    portafolio <- cbind(portafolio, data)
  }
}
## time series starts 2000-01-03
## time series ends   2023-12-29
## time series starts 2000-01-03
## time series ends   2023-12-29
## time series starts 2000-01-03
## time series ends   2023-12-29
## time series starts 2000-01-03
## time series ends   2023-12-29
## time series starts 2000-01-03
## time series ends   2023-12-29
## time series starts 2000-01-03
## time series ends   2023-12-29
## time series starts 2000-01-03
## time series ends   2023-12-29
## time series starts 2000-01-03
## time series ends   2023-12-29
# Asigna nombres de columna al portafolio
colnames(portafolio) <- tickets

# Extraemos la fecha de la base (para gráficar)
Fecha <- time(portafolio)

# Imprime el resultado
head(portafolio)
##                  KO      PEP      JNJ      WMT      TGT      AAPL     MSFT
## 2000-01-03 14.54958 20.37322 24.88615 43.55594 22.83884 0.8472067 36.13227
## 2000-01-04 14.56571 19.85525 23.97506 41.92617 21.84843 0.7757788 34.91170
## 2000-01-05 14.69476 19.37182 24.22814 41.07053 21.35323 0.7871309 35.27981
## 2000-01-06 14.71090 20.23509 24.98738 41.51871 20.34301 0.7190138 34.09800
## 2000-01-07 15.67871 20.78760 26.05032 44.65603 21.39284 0.7530728 34.54361
## 2000-01-10 15.17868 20.37322 25.39231 43.84114 20.97687 0.7398279 34.79546
##                AMZN
## 2000-01-03 4.468750
## 2000-01-04 4.096875
## 2000-01-05 3.487500
## 2000-01-06 3.278125
## 2000-01-07 3.478125
## 2000-01-10 3.459375

Teniendo ya conformada la cartera, visualizamos la evolución histórica de cada serie

# Creamos un reshape "wide to long" para facilitar la graficación
portafolio_long <- cbind(Fecha,as_tibble(portafolio)) %>%
  gather(key = "Ticket", value = "Precio", -Fecha)

# Creamos el gráfico de series de tiempo
int_plot_portafolio <- ggplot(portafolio_long, 
                              aes(x = Fecha, y = Precio, group = Ticket, color = Ticket)) +
  geom_line(aes(y = Precio)) +
  facet_wrap(~Ticket, scales = "free_y") +
  labs(title = "Evolución Histórica",
       x = "Fecha", y = "Precio $USD") +
  scale_color_calc() +
  theme_minimal() +
  theme(axis.title.x = element_text(size = 15, face = "bold"),
        axis.title.y = element_text(size = 15, face = "bold"),
        plot.title = element_text(size = 20, face = "bold", hjust = 0.5),
        axis.text.x = element_text(face = "bold", vjust = 1),
        legend.position = "none")
  
# Agregamos la interacción
ggplotly(int_plot_portafolio)

Posterior a esto, crearemos los beneficios de cada serie (incluida el S&P 500), añadiendo además una normalización logartímica para reescalar la muestra.

# Diferenciamos la cartera
dif_log_portafolio <- round(diff(log(portafolio)), digits = 6)
head(dif_log_portafolio)
##                   KO       PEP       JNJ       WMT       TGT      AAPL
## 2000-01-04  0.001108 -0.025753 -0.037298 -0.038136 -0.044333 -0.088077
## 2000-01-05  0.008821 -0.024649  0.010501 -0.020619 -0.022926  0.014527
## 2000-01-06  0.001097  0.043599  0.030856  0.010853 -0.048466 -0.090514
## 2000-01-07  0.063715  0.026938  0.041659  0.072845  0.050319  0.046281
## 2000-01-10 -0.032412 -0.020135 -0.025584 -0.018417 -0.019636 -0.017744
## 2000-01-11  0.033441 -0.003396  0.003317 -0.014982  0.029769 -0.052506
##                 MSFT      AMZN
## 2000-01-04 -0.034364 -0.086884
## 2000-01-05  0.010489 -0.161039
## 2000-01-06 -0.034072 -0.061914
## 2000-01-07  0.012984  0.059222
## 2000-01-10  0.007264 -0.005405
## 2000-01-11 -0.025946 -0.035866
# Diferenciamos el indice S&P 500
dif_log_SP500 <- round(diff(log(SP500)), digits = 6)
head(dif_log_SP500)
##                SP500
## 2000-01-04 -0.039099
## 2000-01-05  0.001920
## 2000-01-06  0.000955
## 2000-01-07  0.026730
## 2000-01-10  0.011128
## 2000-01-11 -0.013149

Gráficamente esto se ve de la siguiente manera:

# Ajustes a la muestra (formateo de zoo a tibble)
port_SP_long <- merge(dif_log_portafolio,dif_log_SP500)
Time_diff <- time(port_SP_long)

# Creamos un reshape "wide to long" para facilitar la graficación
port_SP_long <- cbind(Time_diff,as_tibble(port_SP_long)) %>%
  gather(key = "Serie", value = "Precio", -Time_diff)

# Creamos el gráfico de series de tiempo
int_plot_port_SP_dif <- ggplot(port_SP_long, 
                              aes(x = Time_diff, 
                                  y = Precio, 
                                  group = Serie, 
                                  color = Serie)) +
  geom_line(aes(y = Precio)) +
  facet_wrap(~Serie, scales = "free_y") +
  labs(title = "Variación Precios Histórica Normalizada",
       x = "Fecha", y = "Precio $USD") +
  scale_color_calc() +
  theme_minimal() +
  theme(axis.title.x = element_text(size = 13, face = "bold"),
        axis.title.y = element_text(size = 13, face = "bold"),
        plot.title = element_text(size = 18, face = "bold", hjust = 0.5),
        axis.text.x = element_text(face = "bold", vjust = 1),
        legend.position = "none")
  
# Agregamos la interacción
ggplotly(int_plot_port_SP_dif)

Posterior a tener las variaciones diarias de cada serie, procedemos a generar los rendimientos promedios, desviación, varianza, covarianza y correlación de las series respectivamente

# Promedios Rendimientos
promedio <- round(sapply(dif_log_portafolio,mean), digits = 6)

# Varianza Rendimientos
varianza <- round(sapply(dif_log_portafolio, var), digits = 6)

# Desviación Rendimientos
desviacion <- round(sapply(dif_log_portafolio, sd), digits = 6)

# Matriz de Varianzas y Covarianzas
covarianzas <- round(cov(dif_log_portafolio), digits = 6)

# Matriz de Correlación
correlacion <- round(cor(dif_log_portafolio) * 100, 2)

# Imprimimos los resultados de Promedio, Varianza y Desviación
recuadro <- rbind(promedio,varianza,desviacion)
formattable(as_tibble(recuadro, rownames = NA))
KO PEP JNJ WMT TGT AAPL MSFT AMZN
promedio 0.000232 0.000351 0.000305 0.000213 0.000303 0.000899 0.000388 0.000584
varianza 0.000171 0.000159 0.000148 0.000220 0.000429 0.000656 0.000371 0.000971
desviacion 0.013067 0.012604 0.012159 0.014817 0.020717 0.025609 0.019251 0.031166
generate_heat_map <- function(correlationMatrix, title)
{
  heatmap.2(
    x = correlationMatrix,
    cellnote = correlationMatrix,
    main = title,
    symm = TRUE,
    dendrogram = "none",
    Rowv = FALSE,
    trace = "none",
    density.info = "none",
    notecol = "black",
    key.title = "Nivel Correlación",
    key.xlab = ""
  )
}

generate_heat_map(correlacion, "Correlaciones Series")

Copyright © 2024 Matías Vicuña Cofré, Todos los Derechos Reservados.